package helper.base.list

import helper.base.string.ToStrHelper

typealias DoubleList = ArrayList<Double>
typealias DoubleListList = ArrayList<DoubleList>

object ArrayListHelper {
    object ArrayExpand {
        fun IntArray.toDoubleArray(
        ): DoubleArray {
            return this.map {
                it.toDouble()
            }.toDoubleArray()
        }

        fun Collection<Int>.toDoubleArray(
        ): DoubleArray {
            return this.toIntArray().toDoubleArray()
        }

        fun Collection<Int>.toDoubleList(
        ): List<Double> {
            return this.map { it.toDouble() }
        }
    }

    object ArrayListExpand {
        fun List<Double>.mathMinus(
            other: List<Double>,
        ): List<Double> {
            return this.zip(other) { a, b ->
                a - b
            }
        }

        fun ArrayList<ArrayList<Double>>.calMean(
        ): ArrayList<Double> {
            val mean = ArrayList<Double>()

            if (isEmpty()) {
                return mean
            }

            val size = size.toDouble()
            val columnSize = this[0].size

            for (i in 0 until columnSize) {
                val sum: Double = sumOf { it[i] }
                mean.add(sum / size)
            }

            return mean
        }

        fun ArrayList<ArrayList<Double>>.toCovarianceMatrix(
        ): ArrayList<ArrayList<Double>> {
            val covarianceMatrix = ArrayList<ArrayList<Double>>()
            if (isEmpty()) {
                return covarianceMatrix
            }
            val mean = calMean()
            val sizeMinusOne = size.toDouble() - 1.0
            val columnSize = this[0].size
            for (i in 0 until columnSize) {
                val row = ArrayList<Double>()
                for (j in 0 until columnSize) {
                    var sum = 0.0
                    for (k in this.indices) {
                        val qi = this[k][i] - mean[i]
                        val qj = this[k][j] - mean[j]
                        sum += qi * qj
                    }
                    val qij = sum / sizeMinusOne
                    row.add(qij)
                }
                covarianceMatrix.add(row)
            }
            return covarianceMatrix
        }
    }

    object ArrayListExpandToStrExpand {
        fun List<Double>.toD0Str(): String {
            val maxWidth = 22
            return "(size=${size})[${
                this.joinToString(",") {
                    it.toString().padStart(maxWidth)
                }
            }]"
        }

        fun List<List<Double>>.toD10Str(
            tabNum: Int = 0,
        ): String {
            val sb = StringBuilder()
            val tsu = ToStrHelper.TabStringUnit.makeTabStringUnit(tabNum)

            sb.append("${tsu.tabNumStr0}(size=${size})[\n")
            this.forEach {
                sb.append("${tsu.tabNumStr1}${it.toD0Str()}\n")
            }
            sb.append("${tsu.tabNumStr0}]\n")

            return sb.toString()
        }
    }
}